package luj.tool.jnproxyan.proxy.network.direct;

import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.handler.codec.http.HttpObject;
import luj.cluster.api.actor.Tellable;
import luj.tool.jnproxyan.framework.proxy.actor.tell.ActorTeller;
import luj.tool.jnproxyan.proxy.network.direct.state.P2sConn;
import luj.tool.jnproxyan.proxy.network.direct.state.P2sConnAttr;
import luj.tool.jnproxyan.proxy.network.https.client.HttpsCliMaker;
import luj.tool.jnproxyan.proxy.network.socks.actor.root.message.http.client2p.response.write.C2pRspWriteMsg;
import luj.tool.jnproxyan.proxy.network.socks.actor.root.message.http.proxy2s.request.write.P2sReqWriteMsg;
import luj.tool.jnproxyan.proxy.network.socks.request.RequestBody;
import luj.tool.jnproxyan.proxy.network.socks.request.SocksRequest;
import luj.tool.jnproxyan.proxy.stats.http.history.HttpHistoryAdder;
import luj.tool.jnproxyan.proxy.stats.http.history.state.HttpHistoryDat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.Instant;

@Component
public class P2sHttpsInitializer {

  public P2sHttpsInitializer inject(Channel conn, SocksRequest socksReq, HttpHistoryDat historyDat, Tellable socksRef) {
    var result = new P2sHttpsInitializer();
    result._conn = conn;

    result._socksReq = socksReq;
    result._socksId = socksReq.getReqId();

    result._historyDat = historyDat;
    result._socksRef = socksRef;

    result._actorTeller = _actorTeller;
    return result;
  }

  public void init() throws Exception {
    RequestBody socksBody = _socksReq.getBody();
    new HttpHistoryAdder(_historyDat, _socksId, socksBody, Instant.now()).add();

    String host = socksBody.getTargetHost();
    int port = socksBody.getTargetPort();
    var httpsCli = new HttpsCliMaker(this::onWebsiteReply, this::onRequestWebsite).make(host, port);

    P2sConn state = new P2sConnAttr(_conn).get();
    state.setHttpsCli(httpsCli);
  }

  /**
   * @see luj.tool.jnproxyan.proxy.network.socks.actor.root.message.http.proxy2s.request.write.OnP2sReqWrite#onHandle
   */
  private void onRequestWebsite(ByteBuf reqData) {
    _actorTeller.inject(_socksRef).tell(P2sReqWriteMsg.class, (b, m) -> b
        .f(m::socksId).set(_socksId)
        .f(m::data).set(reqData)
    );
  }

  /**
   * @see luj.tool.jnproxyan.proxy.network.socks.actor.root.message.http.client2p.response.write.OnC2pRspWrite#onHandle
   */
  private void onWebsiteReply(HttpObject reply) {
    _actorTeller.inject(_socksRef).tell(C2pRspWriteMsg.class, (b, m) -> b
        .f(m::socksId).set(_socksId)
        .f(m::data).set(reply)
    );
  }

//  private static final Logger LOG = LoggerFactory.getLogger(P2sHttpsInitializer.class);

  Channel _conn;

  SocksRequest _socksReq;
  Long _socksId;

  HttpHistoryDat _historyDat;
  Tellable _socksRef;

  @Autowired
  ActorTeller _actorTeller;
}
